<?php
/**
 * 功能：框架入口文件
 * 说明：frame.php
 * 创建日期：
 * 更新日期：
 * 作者：Mirze
 * 补充说明： 
 * 
 */
//记录开始运行时间
$GLOBALS['_beginTime'] = microtime(TRUE);


define('DS', DIRECTORY_SEPARATOR); //DIRECTORY_SEPARATOR 的简写
define('F_DIR', dirname(__FILE__)); //框架基本库所在路径

// 项目名称
//defined('APP_NAME') or define('APP_NAME', basename(dirname($_SERVER['SCRIPT_FILENAME'])));

//$defineArray = require('Init/define.php');
//parse_define($defineArray); //define定义

// 载入核心函数库
require("config/function.php");

//载入全局类名文件
global $G_CLASS_FILES;
if (empty($G_CLASS_FILES)){
    require "config/global_class_files.php";
}

class F {
	var $c = "Index"; //controller
	var $a = "index"; //action	
	
	private static $_objects = array(); //对象注册表
	private static $_ini = array(); //应用程序设置
    private static $_class_path = array(); //类搜索路径
    private static $_class_path_options = array(); //类搜索路径的选项

	/**
	 * (功能描述) 获取指定的设置内容: 如果设置中找不到指定的选项，则返回由 $default 参数指定的值。
	 *
	 * @code php
     * // 获取所有设置项的内容
     * $all = F::ini('/');
	 *
	 * // 查询 option_group 设置组里面的 my_option 项
     * // 将会显示 this is my_option
     * echo Q::ini('option_group/my_option');
     * @endcode
	 *
	 * @param string $option 要获取设置项的名称
     * @param mixed $default 当设置不存在时要返回的设置默认值
     * @return mixed 返回设置项的值
	 */
	static function ini($option, $default = null)
    {
        if ($option == '/') return self::$_ini;

        if (strpos($option, '/') === false) {
            return array_key_exists($option, self::$_ini)
                ? self::$_ini[$option]
                : $default;
        }

        $parts = explode('/', $option);
        $pos =& self::$_ini;
        foreach ($parts as $part) {
            if (!isset($pos[$part])) return $default;
            $pos =& $pos[$part];
        }
        return $pos;
    }

	/**
	 * (功能描述)  替换已有的设置值
	 *
     * @code php
     * // 假设已有的设置为
     * // +--- option_1 = old value
     * // +--- option_group
     * //   +-- option1 = old value
     * //   +-- option2 = old value
     * //   \-- option3 = old value
     *
     * // 替换多个设置项
     * $arr = array(
     *      'option_1' => 'value 1',
     *      'option_2' => 'value 2',
     *      'option_group/option2' => 'new value',
     * );
     * F::replaceIni($arr);
     *
     * // 修改后
     * // +--- option_1 = value 1
     * // +--- option_2 = value 2
     * // +--- option_group
     * //   +-- option2 = new value
     * @endcode
     *
     * @param string|array $option 要修改的设置项名称，或包含多个设置项目的数组
     * @param mixed $data 指定设置项的新值
     */
    static function replaceIni($option, $data = null)
    {
        if (is_array($option)) {
            self::$_ini = array_merge(self::$_ini, $option);
        } else {
            self::$_ini[$option] = $data;
        }
    }

	/**
	 * (功能描述)  删除指定的设置: 可以删除指定的设置项目及其子项目。
     *
     * @param mixed $option 要删除的设置项名称
     */
    static function cleanIni($option)
    {
        if (strpos($option, '/') === false) {
            unset(self::$_ini[$option]);
        } else {
            $parts = explode('/', $option);
            $max = count($parts) - 1;
            $pos =& self::$_ini;
            for ($i = 0; $i <= $max; $i ++) {
                $part = $parts[$i];
                if ($i < $max) {
                    if (!isset($pos[$part])) {
                        $pos[$part] = array();
                    }
                    $pos =& $pos[$part];
                } else {
                    unset($pos[$part]);
                }
            }
        }
    }

	/**
	 * (功能描述)  返回指定对象唯一实例
	 *
	 *   + 在对象注册表中查找指定类名称的对象实例是否存在；
     *   + 如果存在，则返回该对象实例；
     *   + 如果不存在，则载入类定义文件，并构造一个对象实例；
     *   + 将新构造的对象以类名称作为对象名登记到对象注册表；
     *   + 返回新构造的对象实例。
	 *
	 * $obj = F::singleton('My_Object');
	 *
	 * @param string $class_name 要获取对象的类名称
	 * @return object 返回对象实例
	 */
	static function singleton($class_name)
	{
		$key = strtolower($class_name);
		if(isset(self::$_objects[$key])) {
			return self::$_objects[$key];
		}
		
		self::loadClass($class_name);
		return self::register(new $class_name(), $class_name);
	}

	/**
	 * (功能描述) 用特定名字在对象注册表中登记一个对象
	 *
	 * $obj = F::register(new My_Object(), 'obj1');
	 *
	 * @param object $obj 要登记的对象
	 * @param string $name 用什么名字登记
	 * @return object
	 */
	static function register($obj, $name = null)
	{
		if(!is_object($obj)) {
			exit('$obj expected is object');
		}

		if(is_null($name)) {
			$name = get_class($obj);
		}
		$name = strtolower($name);
		self::$_objects[$name] = $obj;

		return $obj;
	}
	
	/**
	 * (功能描述) 在对象注册表中查找指定的对象，不存在抛出
	 *
	 * $obj = F::registry('obj1');
	 *
	 * @param string $name 查找登记名字
	 * @return
	 */
	static function registry($name)
	{
		$name = strtolower($name);
		if(isset(self::$_objects[$name])) {
			return self::$_objects[$name];
		}

		exit('no object is registered of name '. $name);
	}

	/**
	 * (功能描述) 检查指定的对象名字是否在对象注册表中登录
	 *
	 * @param string $name 查找登记名字
	 * @return boolean 
	 */
	static function isRegistered($name)
	{
		$name = strtolower($name);
		return isset(self::$_objects[$name]);
	}

	/**
	 * (功能描述) 载入指定类的定义文件，如果载入失败抛出异常
	 *
	 * @code php
     * F::loadClass('Table_Posts', array('/www/mysite/app', '/www/mysite/lib'));
     * @endcode
     *
     * @param string $class_name 要载入的类
     * @param string|array $dirs 指定载入类的搜索路径
     * @return string|boolean 成功返回类名，失败返回 false
	 */
	static function loadClass($class_name, $dirs = null, $throw = true)
	{
		if (class_exists($class_name, false) || interface_exists($class_name, false)) {
            return $class_name;
        }

        global $G_CLASS_FILES;
        $class_name_l = strtolower($class_name);
        if (isset($G_CLASS_FILES[$class_name_l]))
        {
            require F_DIR . DS . $G_CLASS_FILES[$class_name_l];
            return $class_name_l;
        }

        $filename = str_replace('_', DS, $class_name);
		if ($filename != $class_name) {
            $dirname = dirname($filename);
            if (!empty($dirs)) {
	            if (!is_array($dirs)) {
                    $dirs = explode(PATH_SEPARATOR, $dirs);
                }
            } else {
                $dirs = self::$_class_path;
            }
            $filename = basename($filename) . '.php';
            return self::loadClassFile($filename, $dirs, $class_name, $dirname, $throw);
        } else {
            return self::loadClassFile("{$filename}.php", self::$_class_path, $class_name, '', $throw);
        }
	}

	/**
	 * (功能描述) 添加一个类搜索路径
     *
     * 如果要使用 F::loadClass() 载入非框架的类，需要通过 F::import() 添加类类搜索路径。
     * 要注意，F::import() 添加的路径和类名称有关系。
     *
     * @code php
     * F::import('/www/app');
     * F::loadClass('Vendor_Smarty_Adapter');
     * // 实际载入的文件是 /www/app/vendor/smarty/adapter.php
     *
     * F::import('/www/app/vendor',true);
     * F::loadClass('Zend_Mail');
     * // 实际载入的文件是 /www/app/vendor/Zend/Mail.php
     * @endcode
     *
     * @param string $dir 要添加的搜索路径
     * @param boolean $case_sensitive 在该路径中查找类文件时是否区分文件名大小写
     */
    static function import($dir, $case_sensitive = false)
    {
        $real_dir = realpath($dir);
        if ($real_dir) {
            $dir = rtrim($real_dir, '/\\');
            if (!isset(self::$_class_path[$dir])) {
                self::$_class_path[$dir] = $dir;
                self::$_class_path_options[$dir] = $case_sensitive;
            }
        }
    }

	/**
	 * (功能描述) 载入特定文件，并检查是否包含指定类的定义
     *
     * 该方法从 $dirs 参数提供的目录中查找并载入 $filename 参数指定的文件。
     * 然后检查该文件是否定义了 $class_name 参数指定的类。
     * 如果没有找到指定类，则抛出异常。
     *
     * @code php
     * F::loadClassFile('Smarty.class.php', $dirs, 'Smarty');
     * @endcode
     *
     * @param string $filename 要载入文件的文件名（含扩展名）
     * @param string|array $dirs 文件的搜索路径
     * @param string $class_name 要检查的类
     * @param string $dirname 是否在查找文件时添加目录前缀
     * @param string $throw 是否在找不到类时抛出异常
     */
    static function loadClassFile($filename, $dirs, $class_name, $dirname = '', $throw = true)
    {
        if (!is_array($dirs)) {
            $dirs = explode(PATH_SEPARATOR, $dirs);
        }
        if ($dirname) {
            $filename = rtrim($dirname, '/\\') . DS . $filename;
        }
        $filename_l = strtolower($filename);

        foreach ($dirs as $dir) {
            if (isset(self::$_class_path[$dir])) {
                $path = $dir . DS . (self::$_class_path_options[$dir] ? $filename : $filename_l);
            } else {
                $path = rtrim($dir, '/\\') . DS . $filename;
            }

            if (is_file($path)) {
                require $path;
                break;
            }
        }

        // 载入文件后判断指定的类或接口是否已经定义
        if (!class_exists($class_name, false) && ! interface_exists($class_name, false)) {
            if ($throw) {
                throw new FException($class_name);
            }
            return false;
        }
        return $class_name;
    }

    /**
	 * (功能描述) 载入指定的文件
     *
     * 该方法从 $dirs 参数提供的目录中查找并载入 $filename 参数指定的文件。
     * 如果文件不存在，则根据 $throw 参数决定是否抛出异常。
     *
     * 与 PHP 内置的 require 和 include 相比，F::loadFile() 会多处下列特征：
     * <ul>
     *   <li>检查文件名是否包含不安全字符；</li>
     *   <li>检查文件是否可读；</li>
     *   <li>文件无法读取时将抛出异常。</li>
     * </ul>
     *
     * @code php
     * F::loadFile('my_file.php', $dirs);
     * @endcode
     *
     * @param string $filename 要载入文件的文件名（含扩展名）
     * @param array $dirs 文件的搜索路径
     * @param boolean $throw 在找不到文件时是否抛出异常
     * @return mixed
     */
    static function loadFile($filename, $dirs = null, $throw = true)
    {
        if (preg_match('/[^a-z0-9\-_.]/i', $filename)) {
            throw new FException($filename);
        }
        if (is_null($dirs)) {
            $dirs = array();
        } elseif (is_string($dirs)) {
            $dirs = explode(PATH_SEPARATOR, $dirs);
        }
        foreach ($dirs as $dir) {
            $path = rtrim($dir, '\\/') . DS . $filename;
            if (is_file($path)) return include $path;
        }

        if ($throw) throw new FException($filename);
        return false;
    }

	/**
	 * (功能描述) 对字符串或数组进行格式化，返回格式化后的数组
     *
     * $input 参数如果是字符串，则首先以“,”为分隔符，将字符串转换为一个数组。
     * 接下来对数组中每一个项目使用 trim() 方法去掉首尾的空白字符。最后过滤掉空字符串项目。
     *
     * 该方法的主要用途是将诸如：“item1, item2, item3” 这样的字符串转换为数组。
     *
     * @code php
     * $input = 'item1, item2, item3';
     * $output = F::normalize($input);
     * // $output 现在是一个数组，结果如下：
     * // $output = array(
     * //   'item1',
     * //   'item2',
     * //   'item3',
     * // );
     *
     * $input = 'item1|item2|item3';
     * // 指定使用什么字符作为分割符
     * $output = F::normalize($input, '|');
     * @endcode
     *
     * @param array|string $input 要格式化的字符串或数组
     * @param string $delimiter 按照什么字符进行分割
     * @return array 格式化结果
     */
	static function normalize($input, $delimiter = ',')
    {
        if (!is_array($input)) {
            $input = explode($delimiter, $input);
        }
        $input = array_map('trim', $input);
        return array_filter($input, 'strlen');
    }

	 /**
	 * (功能描述) 注册或取消注册一个自动类载入方法
	 *
     * @param string $class 提供自动载入服务的类
     * @param boolean $enabled 启用或禁用该服务
     */
    static function registerAutoload($class = 'F', $enabled = true)
    {
        if (!function_exists('spl_autoload_register')) {
            require_once F_DIR . '/core/exception.php';
            throw new FException('spl_autoload does not exist in this PHP installation');
        }

        if ($enabled === true) {
            spl_autoload_register(array($class, 'autoload'));
        } else {
            spl_autoload_unregister(array($class, 'autoload'));
        }
    }

	/**
	 * (功能描述) 用于 框架 的类自动载入，不需要由开发者调用
     *
     * @param string $class_name
     */
    static function autoload($class_name)
    {
        self::loadClass($class_name, null, false);
    }


	


}

F::registerAutoload();

?>